package com.mapfinal.api.controller;

import java.util.List;

import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKTReader;

import com.jfinal.aop.Clear;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import com.lambkit.common.service.ServiceKit;
import com.lambkit.web.controller.LambkitController;
import com.mapfinal.api.service.GeoApiService;

/**
 * 测试用例：
 * /api/dwithin/main:mapTownPoint-0101000000410702092F745D406A14D4E8BCFA3F40-60000
 * /api/dwithin?layer=main:mapTownPoint&geometry=POINT(117.8153708%2031.97944503)
 * @author Henry Yang 杨勇 (gismail@foxmail.com)
 * @version 1.0
 * @Package com.mapfinal.api.controller
 */
public class MapApiController extends LambkitController {

	public void index() {
		renderText("hello api!");
	}
	
	private Kv appParas() {
		String layerName = getPara(0, getPara("layer"));
		if(StrKit.isBlank(layerName)) {
			Ret ret = Ret.fail("Msg", "layer error");
			ret.set("ErrorCode", 1);
			ret.set("ErrorMsg", "layer name is null or emptry!");
			ret.set("dataCount", -1);
			renderJson(ret);
			return Kv.by("flag", false);
		}
		Geometry geometry = null;
		String wkt = getPara(1);
		if(StrKit.isBlank(wkt)) {
			wkt = getPara("geometry");
			if(StrKit.isBlank(wkt)) {
				Ret ret = Ret.fail("Msg", "geometry param error");
				ret.set("ErrorCode", 1);
				ret.set("ErrorMsg", "geometry is null or emptry!");
				ret.set("dataCount", -1);
				renderJson(ret);
				return Kv.by("flag", false);
			}
			try {
				geometry = new WKTReader().read(wkt);
			} catch (ParseException e) {
				e.printStackTrace();
				Ret ret = Ret.fail("Msg", "geometry read error");
				ret.set("ErrorCode", 1);
				ret.set("ErrorMsg", e.getMessage());
				ret.set("dataCount", -1);
				renderJson(ret);
				return Kv.by("flag", false);
			}
		} else {
			try {
				byte[] aux = WKBReader.hexToBytes(wkt);
				geometry = new WKBReader().read(aux);
			} catch (ParseException e) {
				e.printStackTrace();
				Ret ret = Ret.fail("Msg", "geometry read error");
				ret.set("ErrorCode", 1);
				ret.set("ErrorMsg", e.getMessage());
				ret.set("dataCount", -1);
				renderJson(ret);
				return Kv.by("flag", false);
			}
		}
		if(geometry==null) {
			Ret ret = Ret.fail("Msg", "geometry read error");
			ret.set("ErrorCode", 1);
			ret.set("ErrorMsg", "geometry read is null, check param : " + wkt);
			ret.set("dataCount", -1);
			renderJson(ret);
			return Kv.by("flag", false);
		}
		return Kv.by("flag", true).set("layer", layerName).set("geometry", geometry);
	}
	
	/**
	 * ST_Distance(geometry, geometry)
	返回两个几何对象的距离（笛卡儿距离），不使用索引。
	 */
	public void distance() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.distance(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_DWithid(geometry, geometry, float)
	如果一个几何对象(geometry)在另一个几何对象描述的距离(float)内，返回TRUE。如果有索引，会用到索引。
	 */
	public void dwithin() {
		System.out.println("dwithin");
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			System.out.println("action for layer: " + layerName);
			Float radius = getParaToFloat(2, getParaToFloat("radius", 2000F));
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.dwithin(layerName, geometry, radius);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Equals(geometry, geometry)
	如果两个空间对象相等，则返回TRUE。用这个函数比用“=”更好，例如：
	equals(‘LINESTRING(0 0, 10 10)’,‘LINESTRING(0 0, 5 5, 10 10)’) 返回 TRUE。
	 */
	public void equals() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.equals(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Disjoint(geometry, geometry)
	如果两个对象不相连，则返回TRUE。不要使用GeometryCollection作为参数。
	 */
	public void disjoin() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.disjoin(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Intersects(geometry, geometry)
	判断两个几何空间数据是否相交,如果相交返回true,不要使用GeometryCollection作为参数。
	Intersects(g1, g2 ) --> Not (Disjoint(g1, g2 ))
	不使用索引可以用_ST_Intersects.
	 */
	public void intersects() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.intersects(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Touches(geometry, geometry)
	如果两个几何空间对象存在接触，则返回TRUE。不要使用GeometryCollection作为参数。
	a.Touches(b) -> (I(a) intersection I(b) = {empty set} ) and (a intersectionb) not empty
	不使用索引可以用_ST_Touches.
	 */
	public void touches() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.touches(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Crosses(geometry, geometry)
	如果两个几何空间对象存在交叉，则返回TRUE。不要使用GeometryCollection作为参数。
	不使用索引可以用_ST_Crosses.
	 */
	public void crosses() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.crosses(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Within(geometry A, geometry B)
	如果几何空间对象A存在空间对象B中,则返回TRUE,不要使用GeometryCollection作为参数。
	不使用索引可以用_ST_Within
	 */
	public void within() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.within(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Overlaps(geometry, geometry)
	如果两个几何空间数据存在交迭,则返回 TRUE,不要使用GeometryCollection作为参数。
	不使用索引可以用_ST_Overlaps.
	 */
	public void overlaps() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.overlaps(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Contains(geometry A, geometry B)
	如果几何空间对象A包含空间对象B,则返回 TRUE,不要使用GeometryCollection作为参数。
	这个函数类似于ST_Within(geometry B, geometryA)
	不使用索引可以用_ST_Contains.
	 */
	public void contains() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.contains(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_Covers(geometry A, geometry B)
	如果几何空间对象B中的所有点都在空间对象A中,则返回 TRUE。
	不要使用GeometryCollection作为参数。
	不使用索引可以用_ST_Covers.
	 */
	public void covers() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.covers(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
	/**
	 * ST_CoveredBy(geometry A, geometry B)
	如果几何空间对象A中的所有点都在空间对象B中,则返回 TRUE。
	 */
	public void coveredby() {
		Kv data = appParas();
		if(data.isTrue("flag")) {
			String layerName = data.getStr("layer");
			Geometry geometry = (Geometry) data.get("geometry");
			GeoApiService service = ServiceKit.inject(GeoApiService.class);
			List<Record> records = service.coveredby(layerName, geometry);
			Ret ret = Ret.ok("Msg", "ok");
			ret.set("ErrorCode", 0);
			ret.set("ErrorMsg", "");
			ret.set("dataCount", records==null ? 0 : records.size());
			ret.set("data", records);
			renderJson(ret);
		}
	}
	
}
